package com.atguigu.gmall.activity.receiver;

import com.atguigu.gmall.activity.mapper.SeckillGoodsMapper;
import com.atguigu.gmall.activity.service.SeckillGoodsService;
import com.atguigu.gmall.activity.util.DateUtil;
import com.atguigu.gmall.common.constant.MqConst;
import com.atguigu.gmall.common.constant.RedisConst;
import com.atguigu.gmall.model.activity.SeckillGoods;
import com.atguigu.gmall.model.activity.UserRecode;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.rabbitmq.client.Channel;
import lombok.SneakyThrows;
import org.springframework.amqp.core.Message;
import org.springframework.amqp.rabbit.annotation.Exchange;
import org.springframework.amqp.rabbit.annotation.Queue;
import org.springframework.amqp.rabbit.annotation.QueueBinding;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;
import org.springframework.util.CollectionUtils;

import java.util.Date;
import java.util.List;

/**
 * @author mqx
 * 监听发送过来的消息
 * @date 2020-8-18 09:38:21
 */
@Component
public class SeckillReceiver {

    // 注入mapper
    @Autowired
    private SeckillGoodsMapper seckillGoodsMapper;

    @Autowired
    private RedisTemplate redisTemplate;

    @Autowired
    private SeckillGoodsService seckillGoodsService;



    @SneakyThrows
    @RabbitListener(bindings = @QueueBinding(
            value = @Queue(value = MqConst.QUEUE_TASK_1,durable = "true"),
            exchange = @Exchange(value = MqConst.EXCHANGE_DIRECT_TASK),
            key = {MqConst.ROUTING_TASK_1}
    ))
    public void importItemToRedis(Message message, Channel channel){
        /*
        4.3.1	扫描数据库中是否有秒杀商品
                    什么是秒杀商品？
                    status=1
                    stock_count>0
                    start_time=new Date(); y-m-d
        4.3.2	将扫描到的商品放入到redis
                    hset(key,field,value); key = seckill:goods ,field = skuId, value = seckillGoods
        4.3.3	将秒杀商品的数量放入redis
                    list
        4.3.4	初始化状态位
                    暂无！
         */
        QueryWrapper<SeckillGoods> seckillGoodsQueryWrapper = new QueryWrapper<>();
        seckillGoodsQueryWrapper.eq("status",1).gt("stock_count",0);
        // y-m-d 需要格式化
        seckillGoodsQueryWrapper.eq("DATE_FORMAT(start_time,'%Y-%m-%d')", DateUtil.formatDate(new Date()));
        // 获取到当前秒杀的商品
        List<SeckillGoods> seckillGoodsList = seckillGoodsMapper.selectList(seckillGoodsQueryWrapper);
        // 判断不为空
        if (!CollectionUtils.isEmpty(seckillGoodsList)){
            // 循环遍历
            for (SeckillGoods seckillGoods : seckillGoodsList) {
                // 判断缓存中是否有这个key，如果存在则不放入数据。用什么存储 hash,string set(key,value)
                // RedisConst.SECKILL_GOODS  hset(key,field,value); key = seckill:goods ,field = skuId, value = seckillGoods
                Boolean flag = redisTemplate.boundHashOps(RedisConst.SECKILL_GOODS).hasKey(seckillGoods.getSkuId().toString());
                // 如果true 说明缓存有数据
                if (flag){
                    continue;
                }
                // 商品放入缓存！
                redisTemplate.boundHashOps(RedisConst.SECKILL_GOODS).put(seckillGoods.getSkuId().toString(), seckillGoods);

                // 将秒杀商品的数量放入redis list.
                for (Integer i = 0; i < seckillGoods.getNum(); i++) {
                    // 商品数量放入list中！ leftPush(); rightPop();
                    // key = seckill:stock:skuId
                    redisTemplate.boundListOps(RedisConst.SECKILL_STOCK_PREFIX+seckillGoods.getSkuId())
                            .leftPush(seckillGoods.getSkuId().toString());
                }
                // 通知其他兄弟节点 skuId:1 初始化都是1
                redisTemplate.convertAndSend("seckillpush",seckillGoods.getSkuId()+":1");
            }
            // 手动确认
            channel.basicAck(message.getMessageProperties().getDeliveryTag(),false);

        }
    }
    // 监听队列中的用户
    @SneakyThrows
    @RabbitListener(bindings = @QueueBinding(
            value = @Queue(value = MqConst.QUEUE_SECKILL_USER,durable = "true"),
            exchange = @Exchange(value = MqConst.EXCHANGE_DIRECT_SECKILL_USER),
            key = {MqConst.ROUTING_SECKILL_USER}
    ))
    public void seckill(UserRecode userRecode, Message message, Channel channel){
        // 数据判断
        if(null!=userRecode){
            // 说明有数据！ 开始处理预下单！
            seckillGoodsService.seckillOrder(userRecode.getSkuId(),userRecode.getUserId());
        }
        // 手动ack
        channel.basicAck(message.getMessageProperties().getDeliveryTag(), false);
    }

    // 监听消息
    @SneakyThrows
    @RabbitListener(bindings = @QueueBinding(
            value = @Queue(value = MqConst.QUEUE_TASK_18,durable = "true"),
            exchange = @Exchange(value = MqConst.EXCHANGE_DIRECT_TASK),
            key = {MqConst.ROUTING_TASK_18}
    ))
    public void clearRedis(Message message, Channel channel){
        /*
        1.  秒杀结束之后：删除所有的数据
                时间：
                状态：
        2.  更新数据库中的状态
         */
        QueryWrapper<SeckillGoods> seckillGoodsQueryWrapper = new QueryWrapper<>();
        seckillGoodsQueryWrapper.eq("status",1);
        seckillGoodsQueryWrapper.le("end_time",new Date());
        // 获取到秒杀结束之后的商品数据
        List<SeckillGoods> seckillGoodsList = seckillGoodsMapper.selectList(seckillGoodsQueryWrapper);
        // 遍历
        for (SeckillGoods seckillGoods : seckillGoodsList) {
            // seckill:stock:35 删除库存数
            redisTemplate.delete(RedisConst.SECKILL_STOCK_PREFIX + seckillGoods.getSkuId());
        }
        // seckill:goods
        redisTemplate.delete(RedisConst.SECKILL_GOODS);
        // 如果在下订单结束之后删除了，那么就没有必要了么? 防止意外再次删除！
        redisTemplate.delete(RedisConst.SECKILL_ORDERS);
        // 删除已经下过订单数据
        redisTemplate.delete(RedisConst.SECKILL_ORDERS_USERS);

        // 更新数据 更新状态 1 表示秒杀开始，2 表示秒杀结束
        SeckillGoods seckillGoods = new SeckillGoods();
        seckillGoods.setStatus("2");
        seckillGoodsMapper.update(seckillGoods,seckillGoodsQueryWrapper);

        // 消息确认
        channel.basicAck(message.getMessageProperties().getDeliveryTag(),false);
    }
}
